<!DOCTYPE html>
<html>

<head>
  <META HTTP-EQUIV="Pragma" CONTENT="no-cache">
  <META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
  <META HTTP-EQUIV="Expires" CONTENT="0">
  <meta charset="UTF-8">
  <title>javascript写的表格</title>
  <style type="text/css">
    @import url(./css/main.css);

  </style>
</head>

<body>
  <div class="div-search">
    <div>名称: <input name="name" /></div>
    <div><button class="button-cs button-search" onclick="query()">搜索</button></div>
  </div>
  <div>
    <div class="div-pages">
      <div> 共 <span>1</span> 条 记录, 每页 <span>10</span> 条记录, 共 <span>1</span> 页</div>
      <ul>
        <li>上一页</li>
        <li class="active">1</li>
        <span>...</span>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
        <li>7</li>
        <li>8</li>
        <span>...</span>
        <li>9</li>
        <li>下一页</li>
      </ul>
    </div>
    <table class="div-table">
      <thead>
        <tr>
          <th>序号</th>
          <th data-name="name" class="">
            <div>
              名称
              <span>
                <i class="ascending" onclick="sortChange(this)"></i>
                <i class="descending" onclick="sortChange(this)"></i>
              </span>
            </div>
          </th>
          <th data-name="region" class="">
            <div>区域
              <span>
                <i class="ascending" onclick="sortChange(this)"></i>
                <i class="descending" onclick="sortChange(this)"></i>
              </span>
            </div>
          </th>
          <th data-name="imgs" class="">
            <div>图片
              <span>
                <i class="ascending" onclick="sortChange(this)"></i>
                <i class="descending" onclick="sortChange(this)"></i>
              </span>

            </div>
          </th>
          <th data-name="date1" class="">
            <div>开始时间
              <span>
                <i class="ascending" onclick="sortChange(this)"></i>
                <i class="descending" onclick="sortChange(this)"></i>
              </span>
            </div>
          </th>
          <th data-name="date2" class="">
            <div>结束时间
              <span>
                <i class="ascending" onclick="sortChange(this)"></i>
                <i class="descending" onclick="sortChange(this)"></i>
              </span>
            </div>
          </th>
          <th data-name="delivery" class="">
            <div>是否配送
              <span>
                <i class="ascending" onclick="sortChange(this)"></i>
                <i class="descending" onclick="sortChange(this)"></i>
              </span>
            </div>
          </th>
          <th data-name="resource" class="">
            <div>资源
              <span>
                <i class="ascending" onclick="sortChange(this)"></i>
                <i class="descending" onclick="sortChange(this)"></i>
              </span>
            </div>
          </th>
          <th data-name="remarks">备注</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        <tr style="display:none;">
          <td style="color: #f40;">.......</td>
          <td data-name="name">.......</td>
          <td data-name="region">.......</td>
          <td data-name="imgs">.......</td>
          <td data-name="date1">.......</td>
          <td data-name="date2">.......</td>
          <td data-name="delivery">.......</td>
          <td data-name="resource">.......</td>
          <td data-name="remarks">.......</td>
          <td>
            <button class="button-cs">修改</button>
            <button class="button-cs">删除</button>
          </td>
        </tr>
      </tbody>
    </table>

  </div>
  <div>页脚</div>
  <div class="div-dialog" style="display: none;;">
    <div>
      <p><span>标题</span> <button class="button-cs"
          onclick="viewHideObject(this.parentNode.parentNode.parentNode,false)">X</button> </p>
      <div>
        <form action="/demo/createorupdate" method="post">
          <input name="id" style="display: none;" />
          <div>名称:<input name="name" /></div>
          <div>区域:<select name="region">
              <option value=""></option>
              <option value="区域一">区域一</option>
              <option value="区域二">区域二</option>
            </select>
          </div>
          <div>图片:<input name="imgs" /></div>
          <div>开始时间:<input name="date1" /></div>
          <div>结束时间:<input name="date2" /></div>
          <div>是否支持配送:
            <input type="radio" name="delivery" value=true />支持
            <input type="radio" name="delivery" value=false />不支持
          </div>
          <div>资源:
            <input type="checkbox" name="resource" value="美食/餐厅线上活动" />美食/餐厅线上活动
            <input type="checkbox" name="resource" value="地推活动" />地推活动
            <input type="checkbox" name="resource" value="线下主题活动" />线下主题活动
            <input type="checkbox" name="resource" value="单纯品牌曝光" />单纯品牌曝光
          </div>
          <div>备注:<textarea name="remarks"></textarea> </div>
          <hr>
          <div>
            <button class="button-cs">确定</button>
            <button type="reset" class="button-cs">取消</button>
          </div>
        </form>
      </div>

    </div>

  </div>

</body>
<script type="text/javascript">
  var p = 1, pageSize = 10, orderBy = '', [lis, buttoms, dots] = [[], [], []];

  function sortChange (o) {
    const [pr, name, self, other] = [o.parentNode.parentNode.parentNode, o.parentNode.parentNode.parentNode.getAttribute('data-name'), /ascending/.test(o.className) ? 'ascending' : 'descending', !/ascending/.test(o.className) ? 'ascending' : 'descending']
    pr.className = new RegExp(self).test(pr.className) ? pr.className.replace(self, '') : pr.className.replace(other, '') + ' ' + self
    let sort = false
    pr.className.replace(/(ascending|descending)/g, ($all, $1) => { sort = /ascending/.test($1) ? 'ASC' : /descending/.test($1) ? 'DESC' : false; })
    orderBy = orderBy.replace(new RegExp(name + '\\s+[\\w]{3,4}', 'g'), ',').replace(/[,]+/g, ',') + (!sort ? '' : ',' + name + ' ' + sort)
    orderBy = orderBy.replace(/,+/g, ',').replace(/(^[\s|,]*)|([\s|,]*$)/g, '')
    document.querySelector('.div-search .button-search').click();
  }

  function adjstParam (o, param) {
    param = !param ? {} : param;
    returnString = '';
    Array.from(o.querySelectorAll('[name]')).filter(((e, i, arr) => {
      if (/checkbox/.test(e.type)) {
        param[e.name] = typeof param[e.name] === 'undefined' ? [] : param[e.name];
        if (e.checked === true) param[e.name].push(e.value);
      } else {
        param[e.name] = (/radio/.test(e.type) ? arr.find(n => /radio/.test(n.type) && n.name == e.name && n.checked) : e)
        param[e.name] = !param[e.name] || !param[e.name].value ? null : param[e.name].value
      }
    }))
    for (k in param) {
      param[k] = typeof param[k] === 'object' ? JSON.stringify(param[k]) : param[k]
      returnString += k + '=' + (typeof param[k] === 'object' ? (!param[k].json ? JSON.stringify(param[k]) : param[k].join(',')) : param[k]) + '&'
    }

    return returnString.replace(/\&$/g, '')
  }

  function doSubmit (o, tr) {
    ajax(o.action, o.method, adjstParam(o), (r) => {
      // document.querySelector('.div-search [name=id]').value = JSON.parse(r.responseText).rId
      ajax('/demo/list?id=' + JSON.parse(r.responseText).rId, null, null, (r) => {
        initTr(tr, JSON.parse(r.responseText).list[0])
        viewHideObject(fr.parentNode.parentNode.parentNode, false)
      })
    })
  }

  function edit (tr, d) {
    fr = document.querySelector('.div-dialog form')
    fr.reset()
    for (key in d)
      if (!!(obj = fr.querySelector('[name=' + key + ']'))) {
        if (/radio/.test(obj.type)) {
          fr.querySelector('[name=' + key + '][value=' + d[key] + ']').checked = true
        } else if (/(radio)|(checkbox)/.test(obj.type)) {
          d[key].replace(/(^\[)|(\]$|\")/g, '').split(',').forEach(a => {
            fr.querySelectorAll('input[type=checkbox][name=' + key + ']').forEach(checkbox => {
              if (a == checkbox.value)
                checkbox.checked = true
            })
          })
        } else {
          obj.value = d[key]
        }
      }
    fr.querySelector('button:nth-of-type(1)').onclick = () => {
      doSubmit(fr, tr);
      return false;
    }
    viewHideObject(fr.parentNode.parentNode.parentNode, true)
  }

  function del (tr, d) {
    if (window.confirm('确定要删除 名为: ' + d.name + ' 的记录?')) {
      ajax('/demo/delete', 'POST', 'id=' + d.id, (r) => {
        tr.parentNode.removeChild(tr)
        total = document.querySelector('.div-pages > div > span').innerHTML - 1
        document.querySelector('.div-pages > div > span').innerHTML = total
        document.querySelector('.div-pages > div > span:nth-of-type(2)').innerHTML = pageSize
        document.querySelector('.div-pages > div > span:nth-of-type(3)').innerHTML = Math.ceil(total / pageSize)
        document.querySelector('.div-pages > ul > li:nth-last-of-type(2)').innerHTML = Math.ceil(total / pageSize)
      })
    }
  }

  function initTr (tr, d) {
    // console.debug('......d...tr.....',d)
    for (key in d)
      if (typeof (dt = d[key]) !== 'undefined' && !!(td = tr.querySelector(' td[data-name="' + key + '"]'))) {
        if (typeof dt === 'boolean') {
          td.innerHTML = dt + '---'
        } else if (/^\[[^\[|\]+\]$]/.test(dt)) {
          td.innerHTML = dt.replace(/^\[|\]$|"/g, '').split(',') + '....'
        } else {
          td.innerHTML = /date/.test(key) ? new Date(dt).toLocaleDateString() : dt;
        }
      }
    tr.querySelector('td:nth-last-of-type(1) > button:nth-of-type(1)').onclick = (t) => {
      edit(t.target.parentNode.parentNode, d)
    }
    tr.querySelector('td:nth-last-of-type(1) > button:nth-of-type(2)').onclick = (t) => {
      del(t.target.parentNode.parentNode, d)
    }
  }

  function query () {
    param = 'p=' + p / 1 + '&pageSize=' + pageSize / 1 + '&orderBy=' + orderBy
    // param = '?p=' + p + '&pageSize=' + pageSize
    document.querySelectorAll('.div-search [name]').forEach(o => {
      v = o.value.replace(/(^\s*)|(\s*$)/g, '')
      if (!!v)
        param += '&' + o.getAttribute('name') + '=' + v
    })
    ajax('../demo/list?' + param, 'get', JSON.stringify(param), (r) => {
      r = JSON.parse(r.responseText)
      document.querySelector('.div-pages > div > span').innerHTML = r.total
      document.querySelector('.div-pages > div > span:nth-of-type(2)').innerHTML = pageSize
      document.querySelector('.div-pages > div > span:nth-of-type(3)').innerHTML = Math.ceil(r.total / pageSize)
      document.querySelector('.div-pages > ul > li:nth-last-of-type(2)').innerHTML = Math.ceil(r.total / pageSize)
      changePageButtons(Math.ceil(r.total / pageSize))
      //删除上一页数据
      tbody = document.querySelector('.div-table  > tbody');
      tbody.querySelectorAll('tr').forEach((tbodyTr, i) => { if (i > 0) tbody.removeChild(tbodyTr); })
      r.list.forEach((d, i) => {
        tr = tbody.querySelector('tr').cloneNode(true); tr.style.display = '';
        tr.querySelector('td').innerHTML = (i + 1) + (p - 1) * pageSize;
        initTr(tr, d)
        tbody.appendChild(tr)
        if (i == 0) {
          // tr.querySelector('td:nth-last-of-type(1) > button:nth-of-type(1)').click()
        }
      })
    })
  }
  function ajax (url, method, data, callback) {
    //1、创建xmlhttprequest对象
    var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("MSXML2.XMLHTTP.3.0");
    //2、.open(type,url/file,async)
    methodString = !method || (/get/i).test(method) ? 'GET' : 'POST';
    data = !data ? null : data;
    xhr.open(methodString, url, true);
    if (!((/get/i).test(methodString))) {
      // application/x-www-form-urlencoded 浏览器默认
      // application/json 来告诉服务端消息主体是序列化后的 JSON 
      // 字符串multipart/form-data 表单上传文件时
      xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
    }
    //3、两种请求方式onload/onreadystatechange
    // xhr.onload = function(){
    //     console.log(this.responseText);
    // }
    xhr.onreadystatechange = () => {
      if (xhr.status == 200 && xhr.readyState == 4) {
        callback(xhr)
      } else if (this.status == 404) {
        console.error("请求的页面不存在");
      }
    }
    //4、发送请求
    xhr.send(data);
  }

  //初始化分页按钮
  function initPageButtons () {
    document.querySelectorAll('.div-pages ul > *').forEach(o => {
      if (o.tagName === 'SPAN') dots.push(o);
      else if (/\d+/.test(o.innerHTML)) { lis.push(o); o.onclick = (t) => { p = t.target.innerHTML; document.querySelector('.div-search .button-search').click(); } }
      else if (o.tagName === 'LI') { buttoms.push(o); }
    });
  }

  //动态调整分页
  function changePageButtons (pages) {
    halfLis = Math.ceil((lis.length > pages ? pages : lis.length) / 2);
    viewHideObject(dots[0], lis.length < pages && !(p <= halfLis))
    viewHideObject(dots[1], lis.length < pages && !(p > (pages - halfLis)))
    lis.forEach((o, n) => {
      viewHideObject(o, pages > n)
      if (lis.length <= pages && n > 0 && n < lis.length - 1) {
        o.innerHTML = p <= halfLis ? (n + 1) : (p > (pages - halfLis) ? (pages - (lis.length) + n + 1) : (p / 1 + n - halfLis + 1))
      }
      // console.debug('....当前页 p=', p, '....半值 halfLis=', halfLis)
      if (o.innerHTML == p && !/none/.test(o.style.display)) {
        o.parentNode.querySelector('li.active').className = ''
        o.className = 'active'
      }
    })
  }

  //工具函数，隐藏显示元素
  function viewHideObject (o, show) {
    Array.of(o).forEach((e, i) => { e.style.display = (show ? '' : 'none'); })
  }

  initPageButtons();
  document.querySelector('.div-table th[data-name="date1"] i:first-child').click();
</script>

</html>
